/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.commons.cryptography;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * 配置文件加解密工具类
 * @author wangyandong
 */
public class PropertiesEncryptor {
    private static final String DEFAULT_KEY = "password";

    /**
     * 加密处理
     * @param originText 明文
     * @param password 密钥
     * @return
     */
    public static String encrypt(String originText, String password) {
        if (password == null || "".equals(password)) {
            password = DEFAULT_KEY;
        }

        String encryptedText;

        try {
            //获取加密引擎实例
            Cipher cipher = Cipher.getInstance("PBEWithMD5AndDES");
            //将key转换为keySpec
            PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray());
            //获取SecretKey
            SecretKey secretKey = SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(pbeKeySpec);
            //生成随机salt
            byte[] salt = new SecureRandom().generateSeed(8);
            //生成随机向量
            byte[] iv = new SecureRandom().generateSeed(16);
            //引擎初始化并转换
            cipher.init(1, secretKey, new PBEParameterSpec(salt, 1000, new IvParameterSpec(iv)));
            byte[] encryptedBytes = cipher.doFinal(originText.getBytes());
            //连接salt iv encryptedBytes三个数组 作为最后的转换结果
            byte[] result = new byte[salt.length + iv.length + encryptedBytes.length];
            System.arraycopy(salt, 0, result, 0, salt.length);
            System.arraycopy(iv, 0, result, salt.length, iv.length);
            System.arraycopy(encryptedBytes, 0, result, salt.length + iv.length, encryptedBytes.length);
            //转为Base64
            encryptedText = Base64.getEncoder().encodeToString(result);
            return encryptedText;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 解密密文
     * @param cipherText 密文
     * @param password 密钥
     * @return
     */
    public static String decrypt(String cipherText, String password) {
        if (password == null || "".equals(password)) {
            password = DEFAULT_KEY;
        }

        byte[] encryptedMessage = Base64.getDecoder().decode(cipherText);

        int saltStart = 0;
        int saltSize = 8;
        int ivSize = 16;

        byte[] salt = new byte[saltSize];
        System.arraycopy(encryptedMessage, saltStart, salt, 0, saltSize);
        byte[] iv = new byte[ivSize];
        System.arraycopy(encryptedMessage, saltStart + saltSize, iv, 0, ivSize);
        byte[] message = new byte[encryptedMessage.length - saltSize - ivSize];
        System.arraycopy(encryptedMessage, saltStart + saltSize + ivSize, message, 0, message.length);

        try {
            //获取加密引擎实例
            Cipher cipher = Cipher.getInstance("PBEWithMD5AndDES");
            //将key转换为keySpec
            PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray());
            //获取SecretKey
            SecretKey secretKey = SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(pbeKeySpec);
            //生成随机salt
            cipher.init(2, secretKey, new PBEParameterSpec(salt, 1000, new IvParameterSpec(iv)));
            byte[] decryptedBytes = cipher.doFinal(message);
            return new String(decryptedBytes);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
